#!/usr/bin/perl -w

use strict;
use utf8;

use FindBin;
use LWP::UserAgent;
use HTTP::Request::Common qw { POST };
use HTTP::Cookies;
use HTML::TreeBuilder;
use HTML::Entities qw (encode_entities_numeric) ;
use File::Basename;
use Math::Trig qw ( great_circle_destination deg2rad rad2deg);
use Data::Dumper;
use Smart::Comments;
use JSON;
use Time::HiRes qw { tv_interval gettimeofday };
use Cz::Cstocs;
sub utf8_ascii;
*utf8_ascii = new Cz::Cstocs 'utf8', 'ascii';

my $Ua;
our $T = [gettimeofday];
our $Cookies;
### GEOCACHING URL'S 
my $LoginUrl = 'https://www.geocaching.com/login/default.aspx';
my $NearestUrl = 'http://www.geocaching.com/seek/nearest.aspx';
my $NearestMapUrl = 'http://www.geocaching.com/map/default.aspx';
my $DetailUrl = 'http://www.geocaching.com/seek/cache_details.aspx';
my $LogUrl = 'http://www.geocaching.com/seek/log.aspx';
my $TrackUrl = 'http://www.geocaching.com/track/details.aspx';
my $TrackLogUrl = 'http://www.geocaching.com/track/log.aspx';
my $TrackKmlUrl = 'http://www.geocaching.com/kml/tbkml.aspx';
my $GoogleMapsUrl = 'http://maps.google.com/maps/api/geocode/json?sensor=false&address=';
my $cacheDir = "$FindBin::RealBin/tmp/";
my %hconvert = (
	'á'	=> '\x5cx{e1}', 'é' => '\x5cx{e9}','í' => '\x5cx{ed}', 'ý' => '\x5cx{fd}', 'ó' => '\x5cx{f3}', 'ú' => '\x5cx{fa}', 'ů' => '\x5cx{16f}',
);

#===  FUNCTION  ================================================================
#         NAME:  get_page_post
#   PARAMETERS:  url, arrray post 
#      RETURNS:  page content or undef
#  DESCRIPTION:  stahne html zadaneho url metodou post
#     COMMENTS:  none
#===============================================================================

sub get_page_post  {
	### POST: $_[0]
	$T = [gettimeofday];
	$Ua = LWP::UserAgent->new;
	$Cookies = HTTP::Cookies->new unless $Cookies;
	$Ua->cookie_jar($Cookies);
	my $req = POST $_[0], 
		'User-Agent'	=> 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6',
		Content => $_[1];
#	$req->{_content} =~ s/\%24/\$/g;
#	warn Dumper($req);
	my $res = $Ua->request($req);
	## POST how long : how_long()
#	print Dumper($res);
	if ($res->is_success) {
		$Cookies->extract_cookies($res);
		### Cookie: $Cookies
		ws($res->as_string);
		return utf8_ascii($res->as_string);
#		return convert_utf8($res->as_string);
	}
	print "False\n";
	undef;
}


#===  FUNCTION  ================================================================
#         NAME:  get_page_get
#   PARAMETERS:  url
#      RETURNS:  page content or undef 
#  DESCRIPTION:  stahne html zadaneho url metodou get
#     COMMENTS:  none
#===============================================================================

sub get_page_get {
	### GET: $_[0]
	$T = [gettimeofday];
	$Ua = LWP::UserAgent->new;
	$Cookies = HTTP::Cookies->new unless $Cookies;
	$Ua->cookie_jar($Cookies);
	my $req = HTTP::Request->new(GET => $_[0] );
	$req->header('Accept' => 'text/html');
	
	my $res = $Ua->request($req);
	## GET how long : how_long()
#	print Dumper($res);
	if ($res->is_success) {
		$Cookies->extract_cookies($res);
		### Cookie: $Cookies
		ws($res->as_string);
		return utf8_ascii($res->as_string);
#		return convert_utf8($res->as_string);
	}
	undef;
}

#===  FUNCTION  ================================================================
#         NAME:  download_file
#   PARAMETERS:  url
#      RETURNS:  1 | 0
#  DESCRIPTION:  stahne soubor a vrati 1 / 0
#     COMMENTS:  none
#===============================================================================

sub download_file {
	my $ua = LWP::UserAgent->new;
}

#===  FUNCTION  ================================================================
#         NAME:  gc_login
#      PURPOSE:  
#   PARAMETERS:  gc_user_name, gc_password
#      RETURNS:  sessionID
#  DESCRIPTION:  login na stranky geocaching com
#     COMMENTS:  none
#===============================================================================

sub gc_login {
	my @postdata;
#	my $Tree = HTML::TreeBuilder->new();
#	$Tree->parse(get_page_get($LoginUrl));
#	$Tree->eof();
	push @postdata, '__VIEWSTATE' => ''; #$Tree->look_down(_tag => 'input', id => '__VIEWSTATE') ? $Tree->look_down(_tag => 'input', id => '__VIEWSTATE')->attr('value') : '';
	push @postdata, '__EVENTVALIDATION' => ''; # $Tree->look_down(_tag => 'input', id => '__EVENTVALIDATION') ? $Tree->look_down(_tag => 'input', id => '__VIEWSTATE')->attr('value') : '';
	push @postdata,  (
		'ctl00$SiteContent$tbUsername' => shift,
		'ctl00$SiteContent$tbPassword' => shift,
		'ctl00$SiteContent$btnSignIn' => 'Login',
	);
	my $html = get_page_post($LoginUrl,\@postdata);
	if ( $html =~ /password combination does not match/ ) {
		return undef;
	}
	return 1;
}


#===  FUNCTION  ================================================================
#         NAME:  gc_nearest 
#   PARAMETERS: latitude longitude
#      RETURNS:  nearest caches as hash
#  DESCRIPTION:  ????
#===============================================================================

sub gc_nearest {
	my $param = shift;
	my $url = $NearestUrl . "?dist=25&";
	if ( $$param{_type} eq 'oso') { 
		$url .= "$$param{oso}=$$param{oso_value}";
	} else {
		$url .="lat=$$param{lat}&lon=$$param{lon}";
		if (  $$param{map} ) {
			return gc_nearest_map($param);
		}
	}
	if ( $$param{shide} ) {
		$url .= '&f=on';
	}

	my $Tree = HTML::TreeBuilder->new();
	$Tree->parse(get_page_get($url));
	$Tree->eof();
	## parseTree: how_long()
	my (@caches, %cache);
	my $i = 1;
	LOOP:
	foreach ( $Tree->look_down( _tag => 'tr', class => qr/Data BorderTop/) ) {
		my @tds = $_->look_down( _tag => 'td');
		%cache = (
			href 	=> $tds[4]->look_down(_tag => 'a')->attr('href'),
			title 	=> $tds[4]->look_down(_tag => 'span')->as_trimmed_text,
	   );
	   $cache{type}	= $tds[4]->look_down(_tag => 'img')->attr('alt');
#	   $cache{distance} =~ s/((?:E|W|N|S){1,2})(\d.*)/$1 $2/;
		#direction and distance
	   my $dist = $tds[1]->look_down( _tag => 'img', id => qr/ctl00_ContentBody_dlResults_ctl\d{2}_uxDistanceAndHeading/);
		if ( $dist ) {
			$cache{distance} = get_distance($dist->attr('src'));
		}

	   if ( $tds[1]->look_down(_tag => 'img', alt => 'Found It!') ) {
	   		### Found: $cache{title}
	   		$cache{type} = 'FI';
			# preskakuju kdyz filtruji nalezene
			next if $$param{shide};
	   }
	   $cache{type} =~ /(\w{2})/;
	   $cache{type} = uc($1);
	   $cache{href} =~ s/(.*?)guid=(.*)$/$2/;
	   if ( $tds[4]->look_down(_tag => 'a', class => qr/Warning Strike/) ) {
	   		### Archived: $cache{title}
	   		$cache{archived} = 1;
			# preskakuju kdyz filtruji disabled
#			next if $$param{shide};
	   }
	   if ( $tds[4]->look_down(_tag => 'a', class => qr/Strike/) ) {
	   		### Disabled: $cache{title}
	   		$cache{disabled} = 1;
			# preskakuju kdyz filtruji disabled
#			next if $$param{shide};
	   }
	    my @in = $tds[2]->look_down( _tag => 'img');
		if ( scalar(@in) > 1 ) {
	   	### inventory: $cache{title}
			$cache{type} .= 'TB' ;
		}
	   push @caches, { %cache }; 
	   last if scalar(@caches) >= 20;
	}
	## LOOP nearest howlong : how_long()
	if ( scalar(@caches) < 0 && $Tree->look_down( _tag => 'tr', class => 'Data BorderTop') ) {
		### $i
		my @postdata = (
			'__VIEWSTATE' 		=> $Tree->look_down( _tag => 'input', name => '__VIEWSTATE')->attr('value'),
			'__EVENTARGUMENT'	=> '',
			'__EVENTTARGET'		=> 'ctl00$ContentBody$pgrBottom$lbGoToPage_'. ++$i,
		);
		### @postdata
		$Tree = HTML::TreeBuilder->new();
		$Tree->parse(get_page_post($url,\@postdata));
		$Tree->eof();
		goto LOOP;
	}
#	warn Dumper(\@caches);
#	warn $Cookies->as_string;
   return \@caches 
}

sub gc_nearest_map {
	my $param = shift;
	my %urlparam = (
		lat => $$param{lat},
		lng => $$param{lon},
		eo_cb_id => 'ctl00_ContentBody_cbAjax',
		eo_cb_states => '',
	);
	# dostava ctverec o uhlopricce 2 km
	my @latlon = get_destination_square($$param{lat},$$param{lon},4);
	### LATLON: @latlon
	$urlparam{eo_cb_param} = '{"c":1, "m": "", "d": "' . join("\|", @latlon ) . '"}';
	my $url = $NearestMapUrl . '?' . join("&", map( { "$_=$urlparam{$_}"} (keys %urlparam) ));
	my (@caches, %cache);
	my $html = get_page_get($url);
	$html =~ s/\x5c+//sg;
	## $html
	$html =~ /\<ExtraData\>\<\!\[CDATA\[(.*?)\]\]\>\<\/ExtraData\>/;
 	my $json = JSON->new->allow_nonref;
	my $hjson = $json->decode($1);
	## $hjson
	## nearest_map howlong: how_long() 	
	return $$hjson{cs}{cc};
}



#===  FUNCTION  ================================================================
#         NAME:  gc_cache_detail
#   PARAMETERS:  guid for cache
#      RETURNS:  cache detail
#  DESCRIPTION:  get cache information
#     COMMENTS:  uzivatel musi byt prihlasen
#===============================================================================

sub gc_cache_detail {
	my %cache;
	$cache{href} = shift;
	my $Tree = get_gc_cache_detail($cache{href});
	## Tree: $Tree
	if ( $Tree->look_down( _tag => 'span', id => 'ctl00_ContentBody_ErrorText')) {
		 $Tree->look_down( _tag => 'span', id => 'ctl00_ContentBody_ErrorText')->as_trimmed_text =~ /(archived|unavailable)/;
		 $cache{error} = $1;
	} elsif ( $Tree->look_down( _tag => 'head')->look_down(_tag => 'title')->as_trimmed_text =~ /Unpublished/i  ) {
		$cache{error} = 'Unpublished';
	}
	return \%cache if exists $cache{error};

	# title waypoint 
	$cache{title} = $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_CacheName')->as_trimmed_text;
	$cache{waypoint} = $Tree->look_down( _tag => 'span', id => 'ctl00_ContentBody_uxWaypointName')->as_trimmed_text;
	
	#cordinates
	@{\%cache}{ qw { coordinates lat lon } } = get_coord($Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_LatLon')->as_trimmed_text);

	# author
	my $spanauth = $Tree->look_down(
		_tag => 'span',
		class => 'minorCachedetails',
		sub { $_[0]->as_trimmed_text =~ /A\s+cache\s+by/ }
	);
	if ($spanauth) {
		#warn $spanauth->as_trimmed_text;
		$cache{author} = $spanauth->look_down( _tag => 'a')->as_trimmed_text;
	}

	# difficuilty terrain size

#		$cache{author} = $tds[0]->look_down( _tag => 'a')->as_trimmed_text;

		$cache{difficulty} = $Tree->look_down( _tag => 'span', id => "ctl00_ContentBody_uxLegendScale")->look_down( _tag => 'img')->attr('alt'); 
		$cache{difficulty} =~ s/^(.*?)\s*out.*/$1/;
		
		$cache{terrain} = $Tree->look_down( _tag => 'span', id => "ctl00_ContentBody_Localize6")->look_down( _tag => 'img')->attr('alt'); 
		$cache{terrain} =~ s/^(.*?)\s*out.*/$1/;
		
		$cache{size} = $Tree->look_down(_tag => 'div', class=>qr/CacheSize/)->look_down( _tag => 'img', alt => qr/Size:/)->attr('alt');
		$cache{size} =~ s/Size:\s*(.*)$/$1/;

		
	# type size difficuilty terrain
	$cache{type} = $Tree->look_down(_tag => 'img', src => qr/\/images\/WptTypes/ )->attr('alt');
	
	#listing
	$cache{shortdesc} = $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_ShortDescription')->as_trimmed_text if $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_ShortDescription');
	$cache{longdesc} = $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_LongDescription')->as_trimmed_text;
	#hint
	$cache{hinttext} = $Tree->look_down( _tag => 'div', id => 'div_hint')->as_trimmed_text if $Tree->look_down( _tag => 'div', id => 'div_hint');
	
	#logs
	$cache{logid} = $Tree->look_down( _tag => 'a', class => 'lnk', href => qr/\/seek\/log.aspx\?ID=/)->attr('href');
	$cache{logid} =~ s/^.*?log\.aspx\?ID=(\d+).*$/$1/;

	my $table = $Tree->look_down( _tag => 'table', class => 'LogsTable');
	my (@logs, %log);
	foreach ( $table->look_down( _tag => 'tr' ) ){
		next unless $_->look_down( _tag => 'strong');
		%log = ();
		$log{author} = $_->look_down( _tag => 'a', href => qr/\/profile/)->as_trimmed_text if $_->look_down( _tag => 'a', href => qr/\/profile/);
		$log{icon}	= basename( $_->look_down( _tag => 'img')->attr('src') ) if $_->look_down( _tag => 'img');
		$_->look_down( _tag => 'strong')->as_trimmed_text =~ /(\w.*?)\s*by\s*(.*)$/ if $_->look_down( _tag => 'strong');
		$log{date} = $1;
		my $td  = $_->look_down( _tag => 'td');
		$td->look_down( _tag => 'strong')->delete if $_->look_down( _tag => 'strong');
		if ($td->look_down( _tag => 'small') ) {
			foreach ($td->look_down( _tag => 'small')) {
				$_->delete;
			}
		}
		$log{log} = $td->as_trimmed_text;
		push @logs, { %log };
	}
	$cache{LOOP_LOGS} = \@logs;
	
	# additional waypoints
	
	if ( $Tree->look_down( _tag => 'table', id => 'ctl00_ContentBody_Waypoints') ) {
	### Additional waypoints
		$table = $Tree->look_down( 
			_tag => 'table', 
			id => 'ctl00_ContentBody_Waypoints'
		)->look_down( _tag => 'tbody');
		my @tr = $table->look_down( _tag => 'tr');
		my (@aw,@td,%awh);
		my $j = 0;
		for (my $i = 0; $i < scalar(@tr); $i += 2 ) {
			@td = $tr[$i]->look_down(_tag => 'td');
			%awh = (
				lookup => $td[4]->as_trimmed_text,
				name => $td[5]->look_down( _tag => 'a')->as_trimmed_text
			 );
			@{\%awh}{ qw { coordinates lat lon } } = get_coord($td[6]->as_trimmed_text);
			$awh{note} = $tr[$i+1]->look_down(_tag => 'td', colspan => 6 )->as_trimmed_text if $tr[$i+1]->look_down(_tag => 'td', colspan => 6 );
			push @aw, { %awh, awid => $j++ };
		}
		$cache{LOOP_AWS} = \@aw;
	}

	# Inventory
	
	my $inventoryDiv = $Tree->look_down(
		_tag	=> 'div',
		class	=> 'CacheDetailNavigationWidget Spacing',
		sub { $_[0]->look_down( _tag => 'img', alt => 'Inventory' ) }
	);

	if ( $inventoryDiv ) {
		my @lis = $inventoryDiv->look_down( _tag => 'li');
		if ( scalar(@lis) > 0 ) {
			my (@tbs, %tb);
			my $i = 0;
			foreach ( @lis ) {
				%tb = ();
				$tb{img} = $_->look_down( _tag => 'img')-> attr('src') if $_->look_down( _tag => 'img');
				$tb{wid} = $_->look_down( _tag => 'a')->attr('href');
				$tb{wid} =~ s/.*?guid=(.*)$/$1/;
				$tb{name} = $_->look_down( _tag => 'a')->as_trimmed_text;
				$tb{tbid} = $i;
				push @tbs, { %tb };
				$i++;
			}
			$cache{LOOP_TBS} = \@tbs;
		} 
	}

#	print Dumper(\%cache);

	## gc_cache_detail rozebrani  howlong: how_long() 	
	save_cache(\%cache) ;
	## gc_cache_detail ulozeni   howlong: how_long() 	
	return \%cache;
}

sub get_coord {
	my $latlon = shift;
	$latlon =~ /(N|S)\s*(.*?)\s*(E|W)\s*(.*?)\s*$/;
	my $coord = "$1 $2<br />$3 $4";
	return ( $coord, convert_coord($2,$1), convert_coord($4,$3) )
}

sub convert_coord {
	my $m = $_[1] eq 'S' || $_[1] eq 'W' ? -1 : 1;
	$_[0] =~ /(\d+).*?(\d.*)$/;
	return ($1 + $2/60) * $m;
}

#===  FUNCTION  ================================================================
#         NAME:  gc_log_params
#      PURPOSE:  
#   PARAMETERS:  logide
#  DESCRIPTION:  log cache
#===============================================================================

sub gc_log_params {
	my $logid = shift;
	my %params;
	my $Tree = HTML::TreeBuilder->new();
	$Tree->parse(get_page_get($LogUrl . '?ID=' .$logid));
	$Tree->eof();
	$params{__VIEWSTATE} = $Tree->look_down(_tag => 'input', id => '__VIEWSTATE') ? $Tree->look_down(_tag => 'input', id => '__VIEWSTATE')->attr('value') : '';
	if ( $Tree->look_down(_tag => 'select', name => 'ctl00$ContentBody$LogBookPanel1$lbTravelBugs' ) ) {
		my @opt =  $Tree->look_down(_tag => 'select', name => 'ctl00$ContentBody$LogBookPanel1$lbTravelBugs' )->look_down(_tag => 'option');
		foreach (@opt) {
			push @{$params{LOOP_MYTBS}}, {
				value => $_->attr('value'),
				desc => $_->as_text,
			}
		}
	}
	### %params
	return \%params;
}




#===  FUNCTION  ================================================================
#         NAME:  gc_cache_log
#      PURPOSE:  
#   PARAMETERS:  date, text, logid, type
#  DESCRIPTION:  log cache
#===============================================================================

sub gc_cache_log {
	my $logid = shift;
	my @postdata;
	push @postdata, '__VIEWSTATE' => $_[3]; 							# $Tree->look_down(_tag => 'input', id => '__VIEWSTATE') ? $Tree->look_down(_tag => 'input', id => '__VIEWSTATE')->attr('value') : '';
	push @postdata, '__EVENTTARGET' => '';
	push @postdata, '__EVENTARGUMENT' => '';
	push @postdata, '__LASTFOKUS' => '';
	push @postdata,  (
	   	'ctl00$ContentBody$LogBookPanel1$ddLogType' 		=> $_[0],
		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged'	=> $_[1],
		'ctl00$ContentBody$LogBookPanel1$LogButton'			=> 'Submit Log Entry',
		'ctl00$ContentBody$LogBookPanel1$tbLogInfo'			=> $_[2],
		'ctl00$ContentBody$LogBookPanel1$chkEncrypt'			=> '',
		'ctl00$ContentBody$LogBookPanel1$WptSelectCheckBox'			=> '',
	);

	if ( $_[4] && $_[4] != -1 ) {
		push @postdata, 'ctl00$ContentBody$LogBookPanel1$lbTravelBugs' => $_[4];
	}
#		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month'	=> 3,
#		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day'	=> 30,
#		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year'	=> 2010,
	## @postdata
#	warn $LogUrl . '?ID=' . $logid;
	get_page_post($LogUrl . '?ID=' . $logid ,\@postdata);
	warn $Cookies->as_string;
}

#===  FUNCTION  ================================================================
#         NAME:  gc_tb_detail
#      PURPOSE:  
#   PARAMETERS:  tb wid
#  DESCRIPTION:  informace o tb
#===============================================================================

sub gc_tb_detail{
	my $guid = shift;
	my %params;
	my $Tree = HTML::TreeBuilder->new();
	$Tree->parse(get_page_get($TrackUrl . '?guid=' .$guid));
	$Tree->eof();
	$params{name} = $Tree->look_down( _tag => 'span', id => 'ctl00_ContentBody_lbHeading')->as_trimmed_text;
	$params{spotted} = $Tree->look_down(_tag => 'a', id => 'ctl00_ContentBody_BugDetails_BugLocation')->as_trimmed_text if $Tree->look_down(_tag => 'a', id => 'ctl00_ContentBody_BugDetails_BugLocation');
	$params{goal} = $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_BugDetails_BugGoal')->as_trimmed_text if $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_BugDetails_BugGoal');
	$params{detail} = $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_BugDetails_BugDetails')->as_trimmed_text if $Tree->look_down(_tag => 'span', id => 'ctl00_ContentBody_BugDetails_BugDetails');
	$params{wid} = $guid;
	return \%params;
}



#===  FUNCTION  ================================================================
#         NAME:  gc_logtb_params
#      PURPOSE:  
#   PARAMETERS:  tb wid
#  DESCRIPTION:  zjisteni adresy a parametru pro logovani tb
#===============================================================================

sub gc_logtb_params {
	my $wid = shift;
	my %params;
	my $Tree = HTML::TreeBuilder->new();
	$Tree->parse(get_page_get($TrackLogUrl . '?wid=' .$wid));
	$Tree->eof();

	$params{__VIEWSTATE} = $Tree->look_down(_tag => 'input', id => '__VIEWSTATE') ? $Tree->look_down(_tag => 'input', id => '__VIEWSTATE')->attr('value') : '';
	$params{name} = $Tree->look_down(
		_tag	=> 'a',
		href	=> qr/\/track\/details.aspx/
	)->as_trimmed_text;
	$params{wid} = $wid;
	### %params
	return \%params;
}




#===  FUNCTION  ================================================================
#         NAME:  gc_tb_log
#      PURPOSE:  
#   PARAMETERS:  logid, type, date, text, tbcode, __VIEWSTATE
#  DESCRIPTION:  log cache
#===============================================================================

sub gc_tb_log {
	my $wid = shift;
	my @postdata;
	push @postdata, '__VIEWSTATE' => $_[4]; 							# $Tree->look_down(_tag => 'input', id => '__VIEWSTATE') ? $Tree->look_down(_tag => 'input', id => '__VIEWSTATE')->attr('value') : '';
	push @postdata, '__EVENTTARGET' => '';
	push @postdata, '__EVENTARGUMENT' => '';
	push @postdata,  (
	   	'ctl00$ContentBody$LogBookPanel1$ddLogType' 		=> $_[0],
		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged'	=> $_[1],
		'ctl00$ContentBody$LogBookPanel1$LogButton'			=> 'Submit Log Entry',
		'ctl00$ContentBody$LogBookPanel1$tbLogInfo'			=> $_[2],
		'ctl00$ContentBody$LogBookPanel1$tbCode'			=> $_[3],
		'ctl00$ContentBody$LogBookPanel1$chkEncrypt'			=> '',
	);

#		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month'	=> 3,
#		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day'	=> 30,
#		'ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year'	=> 2010,
	## @postdata
#	warn $LogUrl . '?ID=' . $logid;
	get_page_post($TrackLogUrl . '?wid=' . $wid ,\@postdata);
}


#===  FUNCTION  ================================================================
#         NAME:  gc_tb_kml
#      PURPOSE:  
#   PARAMETERS:	wid 
#  DESCRIPTION:  download tb route kml file
#===============================================================================

sub gc_tb_kml {
	my $html = get_page_get($TrackKmlUrl . "?tbguid=" . $_[0]);
 	$html =~ /(\<\?xml.*)$/s;
	$1;
}

#===  FUNCTION  ================================================================
#         NAME:  save_cache
#   PARAMETERS:  cache hash
#      RETURNS:  1/0
#  DESCRIPTION:  save cache hash vi Dumper in file guid.cache
#===============================================================================

sub save_cache {
	my $file = $cacheDir . $_[0]->{href} . '.cache';
	warn $file . "\n";
	open (CACHE, ">$file" ) or die "Couldn't open file: $!\n";
		print CACHE Data::Dumper->Dump([$_[0]],['cache']);
	close CACHE;
}


#===  FUNCTION  ================================================================
#         NAME:  get_gc_cache_detail
#   PARAMETERS:  guid
#      RETURNS:  HTML::TreeBuilder structure for cache detail html page
#===============================================================================
sub get_gc_cache_detail {
	my $url = $DetailUrl;
	# get cache by gc code
	if ( $_[0] =~ /^GC/ ) {
		$url .= '?wp=' . $_[0];
	} else {
		$url .= '?guid=' . $_[0];
	} 
	$url .= "&log=y&decrypt=y";
	my $Tree = HTML::TreeBuilder->new();
	$Tree->parse(get_page_get($url));
	$Tree->eof();
	## gc_cache_detail tree howlong: how_long() 	
	return $Tree;
}


#===  FUNCTION  ================================================================
#         NAME:  hint_decrypt
#   PARAMETERS:  crypted text
#      RETURNS:  decrypted text
#  DESCRIPTION:  decrypt caches additional hints
#===============================================================================
 
sub hint_decrypt {
	my @lit = split '', shift;
	my $rtext = '';
	my ($lc, $uc);
	foreach my $l (@lit) {
		$lc = lc($l) eq $l ? 1 : 0;
		$uc = ord(uc($l));
		if ( $uc > 64 && $uc < 78 ) {
			$l = chr($uc+13);
		}
		if ( $uc > 77 && $uc < 91 ) {
			$l = chr($uc-13); 	
		}
		$l = lc($l) if $lc;
		$rtext .= $l;
	}
	return $rtext;
}

#===  FUNCTION  ================================================================
#         NAME:  get_address_latlon
#   PARAMETERS:  address
#      RETURNS:  hash of addresses with lat and lon
#  DESCRIPTION:  search for addresses with google maps api
#===============================================================================

sub get_address_latlon {
	my (@addresses, %addr);
 	my $json = JSON->new->allow_nonref;
	my $html = get_page_get($GoogleMapsUrl . $_[0]);
	$html =~ /({.*})/s;
	my $hjson = $json->decode($1);
	warn ref($hjson);
	## results: $$hjson{results}

	foreach ( @{$$hjson{results}} ) {
		## $_
		push @addresses, {
			address => $_->{formatted_address},
			lat => $_->{geometry}->{location}->{lat},
			lon => $_->{geometry}->{location}->{lng},
		};
	}
	\@addresses
}

#===  FUNCTION  ================================================================
#         NAME:  get_distance
#   PARAMETERS:  address
#      RETURNS:  direction and distance from png 
#  DESCRIPTION:  
#===============================================================================

sub get_distance {
	$_[0] =~ /^\.\.(.*)$/;
	my ($dir,$dist);
	open ( PNG, "wget -q --output-document=- http://www.geocaching.com$1 | pngtopnm -mix |gocr -|");
	while(<PNG>) {
		chomp;
		if ( /((?:E|W|S|N){1,2})/i) {
			$dir = uc($1);
		}
		if ( /km|mi/i ) {
			$dist = $_;
			$dist =~ tr/SsOol/55001/;

		}
	}
	return "$dir $dist";
}



#---------------------------------------------------------------------------
#  						COOKIES
#---------------------------------------------------------------------------

#===  FUNCTION  ================================================================
#         NAME:  set_cookies
#   PARAMETERS:  $ENV{HTTP_COOKIES} text
#  DESCRIPTION:  set cookies for www.geocaching.com
#     COMMENTS:  posilam to pres locify a generuji cookie
#     SEE ALSO:  n/a
#===============================================================================


sub set_cookies {
	my $cootext = shift;
	if ( $cootext =~ /gc_SessionId=(.*?);/ ) {
		$Cookies = HTTP::Cookies->new;
		$Cookies->set_cookie(0,'ASP.NET_SessionId',$1,'/', 'www.geocaching.com',undef, 1 , undef, undef, 1, { HttpOnly => undef} );
	}
}


#===  FUNCTION  ================================================================
#         NAME:  get_cookies
#      RETURNS:  cookie value for ASP.NET_SessionId
#  DESCRIPTION:  
#     COMMENTS:  none
#     SEE ALSO:  n/a
#===============================================================================
my $cookie;
sub get_cookies {
	return '' unless $Cookies;
	$Cookies->scan(\&get_cookie_value);
	return $cookie;
}

sub get_cookie_value {
	if ( $_[1] eq 'ASP.NET_SessionId' ) {
		$cookie = $_[2];
	}
}

sub ws {
	open ( S, ">/tmp/lastget.html") or die "Couldn't open file: $!\n";
	print S $_[0];
	close S
}


#---------------------------------------------------------------------------
#  ziskani sferickych souradnic
#---------------------------------------------------------------------------
# vraci souradnice minLat, maxLat, minLng, maxLang
sub get_destination_square {
	my $R = 6378;                               # prumer zeme
	my $centerLat = shift;
	my $centerLng = shift;
	my $diagonal = shift;

	my @L = NESW($centerLng,$centerLat);
	
	my ($minLat,$maxLat,$minLng,$maxLng);
	($maxLng,$minLat,undef) = great_circle_destination(@L,deg2rad(315),($diagonal/(2*$R)));
	($minLng,$maxLat,undef) = great_circle_destination(@L,deg2rad(135),($diagonal/(2*$R)));

	return (rad2deg($minLat), rad2deg($maxLat), rad2deg($minLng), rad2deg($maxLng) );
}

sub NESW { 	deg2rad($_[0]), deg2rad(90 - $_[1]) }



#---------------------------------------------------------------------------
#  PREVOD NA UTF8, ktere umi zobrazovat Locify
#---------------------------------------------------------------------------
sub convert_utf8 {
	my $text = shift;
#	my $convertreg = join "\|", map ( { 
#		$a = $_;
#		$a =~ s/(\x5cx(\w{2}))/\\x5cx{?$2}?/g;
#		$a;
#		} keys %hconvert ) ;
	my $convertreg = join "\|", keys %hconvert;
#	warn $text;
	### $convertreg;
	$text =~ s/($convertreg)/$hconvert{$1}/gsex;
	$text;
}

sub how_long {
	my $time = tv_interval($T,[gettimeofday]);
	$T = [gettimeofday];
	return $time;
}

1



